package com.ikingtech.platform.service.job.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ikingtech.framework.sdk.context.constant.SecurityConstants;
import com.ikingtech.framework.sdk.context.event.SystemInitEvent;
import com.ikingtech.framework.sdk.core.response.R;
import com.ikingtech.framework.sdk.job.api.JobApi;
import com.ikingtech.framework.sdk.enums.job.JobStatusEnum;
import com.ikingtech.framework.sdk.job.model.JobDTO;
import com.ikingtech.framework.sdk.job.scheduler.JobScheduler;
import com.ikingtech.framework.sdk.log.embedded.annotation.OperationLog;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.framework.sdk.web.annotation.ApiController;
import com.ikingtech.platform.service.job.entity.JobDO;
import com.ikingtech.platform.service.job.service.repository.JobRepository;
import com.ikingtech.platform.service.job.service.JobService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @author tie yan
 */
@Slf4j
@RequiredArgsConstructor
@ApiController(value = "/job", name = "调度中心", description = "调度中心")
public class JobController implements JobApi {

    private final JobService service;

    private final JobRepository repo;

    private final JobScheduler<JobDO> scheduler;

    /**
     * 启动任务
     * @param job 任务信息
     * @return 返回任务ID
     */
    @Override
    @OperationLog(value = "启动任务", dataId = "#_res.getData()")
    @Transactional(rollbackFor = Exception.class)
    public R<Object> start(JobDTO job) {
        JobDO entity = Tools.Bean.copy(job, JobDO.class);
        entity.setId(Tools.Id.uuid());
        entity.setTenantCode(SecurityConstants.DEFAULT_TENANT_CODE);
        entity.setStatus(JobStatusEnum.RUNNING.name());
        this.repo.save(entity);
        this.scheduler.schedule(this.service.createScheduledJob(entity));
        return R.ok(entity.getId());
    }

    /**
     * 停止任务
     * @param jobId 任务ID
     * @return 响应结果
     */
    @Override
    @OperationLog(value = "停止任务")
    @Transactional(rollbackFor = Exception.class)
    public R<Object> stop(String jobId) {
        // 获取任务实体
        JobDO entity = this.repo.getById(jobId);
        if (null != entity) {
            // 设置任务状态为结束
            entity.setStatus(JobStatusEnum.END.name());
            // 更新任务实体
            this.repo.updateById(entity);
            // 取消任务调度
            this.scheduler.cancel(jobId);
        }
        return R.ok();
    }

    /**
     * 注册系统初始化事件监听器
     */
    @EventListener(SystemInitEvent.class)
    public void systemInitEventListener() {
        // 查询未结束的任务列表
        List<JobDO> entities = this.repo.list(Wrappers.<JobDO>lambdaQuery().ne(JobDO::getStatus, JobStatusEnum.END.name()));
        // 如果存在未结束的任务，则初始化调度器
        if (Tools.Coll.isNotBlank(entities)) {
            this.scheduler.init(Tools.Coll.convertList(entities, this.service::createScheduledJob), this.service::feedback);
        } else {
            // 如果不存在未结束的任务，则初始化空调度器
            this.scheduler.init(new ArrayList<>(), this.service::feedback);
        }
    }
}
